#include "logging.hpp"

#ifdef __CANYON_FLAG_enableLogging

#include <ctime>

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

static std::string get_time(){
    time_t curtime;
    time(&curtime);

    tm * timer = localtime(&curtime);
    std::stringstream res;
    res << timer->tm_year + 1900
        << "-" << timer->tm_mon + 1
        << "-" << timer->tm_mday
        << " LCT " << timer->tm_hour
        << ":" << timer->tm_min
        << ":" << timer->tm_sec;
    
    timer = gmtime(&curtime);
    res << " GMT " << timer->tm_hour
        << ":" << timer->tm_min
        << ":" << timer->tm_sec;
        
    return res.str();
}

namespace canyon::logging{

/* CRUCIAL IMPORTANT LOGGING LEVEL STANDARD SETTING */
static const log_level LOG_LEVEL_STANDARD = log_level::INFO;

template<is_string T>
void log(log_level level, log_metainfo metainfo, T str, std::ostream & stream){
    if(level < LOG_LEVEL_STANDARD) return;
    std::stringstream res;
    res << metainfo.name << " " << metainfo.addr;
    std::string rmetainfo = res.str();
    switch(level){
        case log_level::DEBUG:
            stream << "[DEBUG] [" << get_time() << "] [" << rmetainfo << "] " << str << std::endl;
            break;
        case log_level::INFO:
            stream << "[ INFO] [" << get_time() << "] [" << rmetainfo << "] " << str << std::endl;
            break;
        case log_level::WARN:
            stream << "[ WARN] [" << get_time() << "] [" << rmetainfo << "] " << str << std::endl;
            break;
        case log_level::ERROR:
            stream << "[ERROR] [" << get_time() << "] [" << rmetainfo << "] " << str << std::endl;
            break;
        case log_level::FATAL:
            stream << "[FATAL] [" << get_time() << "] [" << rmetainfo << "] " << str << std::endl;
            break;
    }
    stream.flush();
}

template void log<const char *>(log_level level, log_metainfo metainfo, const char *str, std::ostream & stream);
template void log<std::string>(log_level level, log_metainfo metainfo, std::string str, std::ostream & stream);

template<is_string T>
logstream & logstream::operator<<(T str){
    log(this->level, this->metainfo, str, std::clog);
    return *this;
}

template logstream & logstream::operator<<<const char *>(const char *str);
template logstream & logstream::operator<<<std::string>(std::string str);

logstream & logstream::operator<<(log_signal_level signal){
    this->level = signal.level;
    return *this;
}

}

#endif
